package butines.game2.entity;

import java.awt.Color;
import java.util.List;

import butines.common.math.Vector2D;
import butines.game2.messaging.Message;
import butines.game2.states.State;
import butines.game2.states.StateMachine;
import butines.game2.states.UnitStates;

public class Unit extends EntityMoving {

    private int toGridX;
    private int toGridY;
    
    protected final StateMachine<Unit> stateMachine;
    
    private Sprite animation;
    
    public Unit() {
        animation = new Sprite();
        stateMachine = new StateMachine<Unit>(this);
        stateMachine.setGlobalState(UnitStates.Global.getInstance()).enter(this);
        stateMachine.setCurrentState(UnitStates.Stay.getInstance()).enter(this);
    }
    
    @Override
    public boolean handleMessage(Message message) {
        return stateMachine.handlerMessage(message);
    }

    @Override
    public void update(float dt) {
        
        if (life <= 0) {
            status = Status.DEAD;
            game.removeEntity(this);
            return;
        }
        
        stateMachine.update();
        
        updateMovement();
        
        image = animation.getCurrentImage(heading.x, heading.y);
    }
    
    public void renderDebug(float sx, float sy) {

    	drawer.defaultFont();
        drawer.black();
        drawer.center();
        drawer.print(sx, sy-50, stateMachine.getStateName());
        drawer.print(sx, sy-40, "%.2f", velocity.length());
        drawer.print(sx, sy-30, "%.2f", heading.theta());

        Vector2D l = heading.copy().mult(64).add(position);
        drawer.red();
        drawer.line(position.x, position.y, l.x, l.y);
        
        Vector2D a = new Vector2D(position);
        Vector2D b = new Vector2D(position);
        a.sub(side.copy().mult(32));
        b.add(side.copy().mult(32));
        drawer.red();
        drawer.line(a.x, a.y, b.x, b.y);
        
        if (steering.isFollowPath()) {
            Vector2D last = null;
            drawer.color(Color.RED);
            for (Vector2D vec : steering.getPath().getWaypoints()) {
                drawer.fill();
                drawer.circle(vec.x, vec.y, 3);
                if (last != null) {
                    drawer.line(vec.x, vec.y, last.x, last.y);
                }
                last = vec;
            }
        }
        
    	int w = getGame().getCellSize();
    	int x = (int) (sx / w) * w;
    	int y = (int) (sy / w) * w;
    	drawer.color(255,0,0,95).fill().rect(x, y, w-1, w-1);
    	drawer.red().circle(sx, sy, 3);
        
    }
    
    public void renderSelection(float sx, float sy) {
        if (selected) {

            drawer.color(game.getSelectionFillColor());
            drawer.fill();
            drawer.circle(sx, sy, radius);
            
            drawer.color(game.getSelectionBorderColor());
            drawer.draw();
            drawer.circle(sx, sy, radius);
            
        }
    }
    
    public void renderLifeBar(float sx, float sy) {
        if (selected) {
            float x = sx - radius;
            float y = sy - radius - (game.getHealthBarHeight() * 3);
    
            float lifeBarWidth = radius*2;
            
            if (life > hitPoints * .4f) {
                drawer.color(game.getHealthBarHealthyFillColor());
            } else {
                drawer.color(game.getHealthBarDamagedFillColor());
            }
            
            drawer.fill();
            drawer.rect(x, y, (lifeBarWidth * life / hitPoints), game.getHealthBarHeight());
            
            drawer.color(game.getHealthBarBorderColor());
            drawer.draw();
            drawer.rect(x, y, lifeBarWidth, game.getHealthBarHeight());
        }
    }
    
    private void updateMovement() {
        
        // calculate the combined steering force
        Vector2D force = steering.calculate();

        // if no steering force is produced decelerate the player by applying a braking force
        if (force.isZero()) {
            final float BRAKING_RATE = 0.8f;
            applyBrakingForce(BRAKING_RATE);
        }
        
        applySteeringForce(force);
        
        // if the vehicle has a non zero velocity the heading and side vectors must be updated
        if (!velocity.isZero()) {
            heading.set(velocity).normalise();
            Vector2D.perpendicular(side, heading);
        }
        
    }
       
    public boolean searchPath() {
        List<Vector2D> waypoints = game.searchPath(getGridX(), getGridY(), toGridX, toGridY);
        if (waypoints.size() > 0) {
            steering.getPath().setWaypoints(waypoints);
            return true;
        }
        return false;
    }
    
    public void changeState(State<Unit> newState) {
        stateMachine.changeState(newState);
    }
    
    public boolean animate(Sprite.Type type, boolean loop) {
        return animation.animate(type, loop);
    }
    
    public void checkCollisionObjects() {
        
    }
        
    /** GETTERS AND SETTERS *******************************************/
    public StateMachine<Unit> getStateMachine() {
        return stateMachine;
    }

    public Sprite getAnimation() {
        return animation;
    }

    public int getToGridX() {
        return toGridX;
    }

    public void setToGridX(int toGridX) {
        this.toGridX = toGridX;
    }

    public int getToGridY() {
        return toGridY;
    }

    public void setToGridY(int toGridY) {
        this.toGridY = toGridY;
    }
    
}
